import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateUserDto, DeleteUserDto, EditUserRoles, FindManyUserDto, FindOneUserDto, FrozenUserDto, LoginUserDto, RegisterCaptchaDto, UpdateInfoCaptchaDto, UpdatePass, UpdateUserInfoDto } from './dto/user.dto';
import { PrismaService } from '../prisma/prisma.service';
import { md5 } from 'src/utils';
import { EmailService } from '../email/email.service';
import { ConfigService } from "@nestjs/config"
import dayjs from 'dayjs';
import { JwtService } from '@nestjs/jwt';
import { FastifyRequest } from 'fastify';

@Injectable()
export class UserService {
  constructor(
    private readonly prismaService: PrismaService,
    private readonly emailService: EmailService,
    private readonly configService: ConfigService,
    private readonly jwtService: JwtService,
  ) { }

  // 用户注册
  async register(cud: CreateUserDto) {
    // 比对验证码
    const findCaptcha = await this.prismaService.captcha.findUnique({
      where: { target: cud.email }
    })


    if (findCaptcha?.code !== cud.captcha || dayjs(findCaptcha.expiresAt) < dayjs()) {
      throw new HttpException('验证码错误或已过期', HttpStatus.BAD_REQUEST)
    }

    // 用户名是否存在
    const findUser = await this.prismaService.user.findUnique({
      where: { username: cud.username }
    })
    if (findUser) {
      throw new HttpException('用户名已存在', HttpStatus.BAD_REQUEST)
    }

    // 添加用户到数据库
    const newUser = { ...cud, captcha: undefined }
    newUser.password = md5(cud.password)
    try {
      await this.prismaService.user.create({ data: newUser })
      return "用户注册成功"
    } catch (error) {
      throw new HttpException('用户注册失败', HttpStatus.BAD_REQUEST)
    }
  }

  // 更新用户信息
  async updateUserInfo(uuid: UpdateUserInfoDto) {
    const { userId, username, email, telephone, avatar } = uuid
    if (!userId) {
      throw new HttpException('用户未登录或登录信息失效', HttpStatus.BAD_REQUEST)
    }
    try {
      await this.prismaService.user.update({
        where: { id: userId },
        data: { username, email, telephone, avatar }
      })
      return "用户信息修改成功"
    } catch (error) {
      throw new HttpException('用户信息修改失败', HttpStatus.BAD_REQUEST)
    }
  }

  // 冻结用户
  async frozenUser(fud: FrozenUserDto) {
    const { userId, isFrozen } = fud
    const messageStatus = isFrozen ? "冻结" : "解冻"
    try {
      await this.prismaService.user.update({
        where: { id: userId },
        data: { isFrozen }
      })
      return `用户${messageStatus}成功`
    } catch (error) {
      throw new HttpException(`用户${messageStatus}失败`, HttpStatus.BAD_REQUEST)
    }
  }

  // 获取多个用户
  async findMany(fmd: FindManyUserDto) {
    try {
      const res = await this.prismaService.user.findMany({
        include: {
          roles: {
            include: {
              role: {
                include: {
                  permissions: {
                    include: {
                      permission: true
                    }
                  }
                }
              }
            }
          }
        },
        skip: fmd.page ? ((fmd.page - 1) * fmd.limit) : 0,
        take: fmd.limit,
        orderBy: { [fmd.orderBy]: fmd.orderDirection },
      });
      if (res?.length) {
        const filterPass = res.map((item) => {
          const { password, ...data } = item
          const { roles, permissions } = this.handleRolePermission(item.roles)
          return { ...data, roles, permissions }
        })
        return filterPass
      }
      return res;
    } catch (error) {
      throw new HttpException('获取用户失败', HttpStatus.BAD_REQUEST)
    }
  }

  // 查找指定用户
  async findOne(foud: FindOneUserDto) {
    try {
      const res = await this.prismaService.user.findUnique({ where: { id: foud.id } });
      return res
    } catch (error) {
      throw new HttpException('用户查找失败', HttpStatus.BAD_REQUEST)
    }
  }

  // 删除用户
  async remove(dud: DeleteUserDto) {
    try {
      await this.prismaService.user.delete({ where: { id: dud.id } });
      return "用户删除成功"
    } catch (error) {
      throw new HttpException('用户删除失败', HttpStatus.BAD_REQUEST)
    }
  }

  // 获取验证码
  async captcha(rcd: RegisterCaptchaDto) {

    const findUser = await this.prismaService.user.findUnique({
      where: { email: rcd.email }
    })
    if (rcd.type === 'register' && findUser) {
      throw new HttpException('该邮箱已被注册', HttpStatus.BAD_REQUEST)
    }

    if (rcd.type === 'findPass' && !findUser) {
      throw new HttpException('该邮箱尚未注册', HttpStatus.BAD_REQUEST)
    }

    const code = Math.random().toString().slice(2, 8);

    try {
      // 邮箱
      const configTime = this.configService.get('CAPTCHA_EXPIRESAT')
      await this.emailService.sendMail({
        to: rcd.email,
        subject: '注册验证码',
        html: `<p>你的注册验证码是 ${code}，${configTime}分钟有效期</p>`
      });

      // 数据库
      const expiresAt = new Date(Date.now() + (configTime || 10) * 60 * 1000)
      await this.prismaService.captcha.upsert({
        where: { target: rcd.email },
        create: { target: rcd.email, code, expiresAt },
        update: { code, expiresAt }
      })

      if (rcd.type === 'findPass') {
        return { username: findUser?.username }
      }

      return '邮件已发送，请注意查收';
    } catch (error) {
      throw new HttpException('验证码发送失败', HttpStatus.BAD_REQUEST)
    }
  }

  private async captchaFun(email: string) {

    const code = Math.random().toString().slice(2, 8);
    // 邮箱
    const configTime = this.configService.get('CAPTCHA_EXPIRESAT')
    await this.emailService.sendMail({
      to: email,
      subject: '注册验证码',
      html: `<p>你的注册验证码是 ${code}，${configTime}分钟有效期</p>`
    });

    // 数据库
    const expiresAt = new Date(Date.now() + (configTime || 10) * 60 * 1000)
    await this.prismaService.captcha.upsert({
      where: { target: email },
      create: { target: email, code, expiresAt },
      update: { code, expiresAt }
    })
  }

  // 修改用户信息的验证码
  async updateInfoCaptcha(uicd: UpdateInfoCaptchaDto) {
    const findUser = await this.prismaService.user.findUnique({
      where: { id: uicd.userId }
    })

    if (findUser?.email !== uicd.email) {
      const findEmail = await this.prismaService.user.findUnique({
        where: { email: uicd.email }
      })
      if (findEmail) {
        throw new HttpException('该邮箱已被注册', HttpStatus.BAD_REQUEST)
      }
    }

    try {
      this.captchaFun(uicd.email)
      return '邮件已发送，请注意查收';
    } catch (error) {
      throw new HttpException('验证码发送失败', HttpStatus.BAD_REQUEST)
    }
  }

  // login
  async login(loginDto: LoginUserDto) {
    try {
      const findUser = await this.prismaService.user.findUnique({
        where: { username: loginDto.username },
        include: {
          roles: {
            include: {
              role: {
                include: {
                  permissions: {
                    include: {
                      permission: true
                    }
                  }
                }
              }
            }
          }
        }
      })

      if (!findUser) {
        throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
      }

      if (findUser.password !== md5(loginDto.password)) {
        throw new HttpException('密码错误', HttpStatus.BAD_REQUEST);
      }

      if (findUser.isFrozen) {
        throw new HttpException('该账号已被冻结，请联系管理员', HttpStatus.BAD_REQUEST);
      }

      const { roles, permissions } = this.handleRolePermission(findUser.roles)

      const accessToken = this.jwtService.sign({
        userId: findUser.id,
        username: findUser.username,
        roles,
        permissions
      });

      // 这里使用解构赋值来移除密码字段
      const { password, isFrozen, ...userInfo } = findUser

      return { ...userInfo, accessToken, roles, permissions }
    } catch (error) {
      const message = error?.response || '登录失败';
      throw new HttpException(message, HttpStatus.BAD_REQUEST);
    }
  }

  // 编辑用户角色
  async editUserRoles(eurs: EditUserRoles) {
    try {
      await this.prismaService.user.update({
        where: { id: eurs.id },
        data: {
          roles: {
            deleteMany: {},
            create: eurs.roles.map((rid: any) => ({
              roleId: rid.id
            }))
          }
        }
      })
      return "角色编辑成功"
    } catch (error) {
      throw new HttpException('编辑角色失败', HttpStatus.BAD_REQUEST);
    }
  }

  // 更新密码
  async updatePass(upss: UpdatePass) {
    try {
      // 比对验证码
      const findCaptcha = await this.prismaService.captcha.findUnique({
        where: { target: upss.email }
      })

      if (findCaptcha?.code !== upss.captcha || dayjs(findCaptcha.expiresAt) < dayjs()) {
        throw new HttpException('验证码错误或已过期', HttpStatus.BAD_REQUEST)
      }
      await this.prismaService.user.update({
        where: { email: upss.email },
        data: {
          password: md5(upss.password)
        }
      })
      return "密码重置成功"
    } catch (error) {
      throw new HttpException(error.response, HttpStatus.BAD_REQUEST);
    }
  }

  // 获取用户信息
  async getUserInfo(req: FastifyRequest) {
    const authorization = req.headers.authorization
    if (authorization) {
      const userInfo = this.jwtService.verify(authorization)
      if (!userInfo || !userInfo.userId) {
        throw new HttpException('用户信息验证失败', HttpStatus.UNAUTHORIZED)
      }

      const { userId } = userInfo;
      try {
        const res = await this.prismaService.user.findUnique({
          where: { id: userId },
          include: {
            roles: {
              include: {
                role: {
                  include: {
                    permissions: {
                      include: {
                        permission: true
                      }
                    }
                  }
                }
              }
            }
          }
        });
        if (!res) {
          throw new HttpException('用户信息查找失败', HttpStatus.BAD_REQUEST);
        }
        if (res.isFrozen) {
          throw new HttpException('该账号已被冻结，请联系管理员', HttpStatus.BAD_REQUEST);
        }
        const { roles, permissions } = this.handleRolePermission(res.roles)

        const { password, isFrozen, ...userData } = res
        return { ...userData, permissions, roles }
      } catch (error) {
        throw new HttpException('用户信息查找失败', HttpStatus.BAD_REQUEST)
      }
    }
  }

  handleRolePermission = (rolesRes: any) => {
    const userPermissions = rolesRes
      .flatMap(item => item.role?.permissions || [])
      .map(rp => rp.permission?.code)
      .filter(Boolean);
    const permissions = [...new Set(userPermissions)];
    const roles = rolesRes.map(item => item.role?.name).filter(Boolean);
    return { roles, permissions };
  }
}

